import { tween } from "cc";



//贝塞尔曲线运动轨迹工具 目前只支持二阶(U形轨迹)与三阶(S形轨迹)
export class BezierUtil {
    //贝塞尔曲线公式  t是进度 指在0~1之间   start是起点    p1 p2 是锚点    end是终点    pt是当前进度的位置  
    //二阶  pt=(1-t)*(1-t)*start + 2*t*(1-t)*p1 + t*t*end          
    //三阶  pt=(1-t)*(1-t)*(1-t)*start + 3*t*(1-t)*(1-t)*p1 + 3*t*t*(1-t)*p2 + t*t*t*end


    /**
     * 二阶贝塞尔曲线运动     用在坐标上描述节点运动轨迹时 x与y 要分开 各自使用独立的公式来处理   x = (1-tx)*(1-tx)*startX + 2*tx*(1-tx)*x1 + t*t*endX      与    y = (1-ty)*(1-ty)*startY + 2*ty*(1-ty)*y1 + t*t*endY 
     * @param start 起点值
     * @param p1 锚点值
     * @param end 终点值
     * @param duration 总持续时长(秒)
     * @param thisObj 传给回调的this引用
     * @param update 同步回调 将传入当前值
     * @param complete 完成回调 你也可以通过 .then() 来回调你的完成时方法
     * @returns
     * 
     */
    static quadratic(start: number, p1: number, end: number, duration: number, thisObj?: any, update?: (v: number) => any, complete?: (v: number) => any): Promise<void> {
        return new Promise<void>(resolve => {
            const tweenObj = { t: 0 };
            tween(tweenObj).to(duration, { t: 1 }, {
                onUpdate: (obj, t) => {
                    if (update) {
                        // @ts-ignore
                        let tx = 1 - t;
                        // @ts-ignore
                        let value = tx * tx * start + 2 * t * tx * p1 + t * t * end;
                        update.call(thisObj, value);
                    }
                },
                onComplete: () => {
                    if (complete) {
                        complete.call(thisObj, end);
                    }
                    resolve();
                }
            }).start();
        })
    }

    /**
     * 三阶贝塞尔曲线运动     用在坐标上描述节点运动轨迹时 x与y 要分开 各自使用独立的公式来处理   x = (1-tx)*(1-tx)*(1-tx)*startX + 3*tx*(1-tx)*(1-tx)*x1 + 3*tx*tx*(1-tx)*x2 + tx*tx*tx*endX      与    y = (1-ty)*(1-ty)*(1-ty)*startY + 3*ty*(1-ty)*(1-ty)*y1 + 3*ty*ty*(1-ty)*y2 + ty*ty*ty*endY
     * @param start 起点值
     * @param p1 锚点值1
     * @param p2 锚点值2
     * @param end 终点值
     * @param duration 总持续时长(秒)
     * @param thisObj 传给回调的this引用
     * @param update 同步回调 将传入当前值
     * @param complete 完成回调 你也可以通过 .then() 来回调你的完成时方法
     * @returns
     * 
     */
    static cubic(start: number, p1: number, p2: number, end: number, duration: number, thisObj?: any, update?: (v: number) => any, complete?: (v: number) => any): Promise<void> {
        return new Promise<void>(resolve => {
            const tweenObj = { t: 0 };
            tween(tweenObj).to(duration, { t: 1 }, {
                onUpdate: (obj, t) => {
                    if (update) {
                        // @ts-ignore
                        let tx = 1 - t;
                        // @ts-ignore
                        let value = tx * tx * tx * start + 3 * t * tx * tx * p1 + 3 * t * t * tx * p2 + t * t * t * end;
                        update.call(thisObj, value);
                    }
                },
                onComplete: () => {
                    if (complete) {
                        complete.call(thisObj, end);
                    }
                    resolve();
                }
            }).start();
        })
    }
}